home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / SpaceballViewer / MySlider.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  15.9 KB  |  638 lines

  1. /*
  2.  * Copyright (c) 1990-94 Silicon Graphics, Inc.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that the name of Silicon Graphics may not be used in any advertising or
  7.  * publicity relating to the software without the specific, prior written
  8.  * permission of Silicon Graphics.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  11.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  12.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  13.  *
  14.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  15.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
  17.  * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  */
  20. /*
  21.  * Copyright (C) 1990-93   Silicon Graphics, Inc.
  22.  *
  23.  _______________________________________________________________________
  24.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  25.  |
  26.  |   $Revision: 1.1023 $
  27.  |
  28.  |   Classes:
  29.  |    MySlider
  30.  |
  31.  |   Author(s)    : Alain Dumesny
  32.  |
  33.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  34.  _______________________________________________________________________
  35.  */
  36.  
  37. #include <stream.h>
  38. #include <malloc.h>
  39.  
  40. #include <X11/StringDefs.h>
  41. #include <X11/Intrinsic.h>
  42. #include <Xm/Form.h>
  43. #include <Xm/Text.h>
  44. #include <Xm/Label.h>
  45. #include <Xm/LabelG.h>
  46.  
  47. #include <Inventor/Xt/SoXt.h>
  48. #include <Inventor/Xt/devices/SoXtMouse.h>
  49. #include <Inventor/errors/SoDebugError.h>
  50. #include "MyUIRegion.h"
  51. #include "MyFloatCallbackList.h"
  52. #include "MySlider.h"
  53.  
  54. #include <GL/gl.h>
  55.  
  56.  
  57. /*
  58.  * Defines
  59.  */
  60.  
  61. #define BOX_H        12        // thum height
  62. #define BOX_L        7        // thum width/2
  63. #define SPACE        2
  64. #define THUMB_SPACE 1
  65. #define SIDE        (UI_THICK + SPACE + UI_THICK)
  66.  
  67. // pixels between the slider and the label
  68. #define TEXT_OFFSET 6
  69.  
  70. ////////////////////////////////////////////////////////////////////////
  71. //
  72. // Public constructor - build the widget right now
  73. //
  74. MySlider::MySlider(
  75.     Widget parent,
  76.     const char *name, 
  77.     SbBool buildInsideParent)
  78.     : SoXtGLWidget(
  79.         parent,
  80.         name, 
  81.         buildInsideParent, 
  82.         SO_GLX_RGB, 
  83.         FALSE) // tell GLWidget not to build just yet  
  84. //
  85. ////////////////////////////////////////////////////////////////////////
  86. {
  87.     // In this case, this component is what the app wants, so buildNow = TRUE
  88.     constructorCommon(TRUE);
  89. }
  90.  
  91. ////////////////////////////////////////////////////////////////////////
  92. //
  93. // SoEXTENDER constructor - the subclass tells us whether to build or not
  94. //
  95. MySlider::MySlider(
  96.     Widget parent,
  97.     const char *name, 
  98.     SbBool buildInsideParent, 
  99.     SbBool buildNow)
  100.     : SoXtGLWidget(
  101.         parent,
  102.         name, 
  103.         buildInsideParent, 
  104.         SO_GLX_RGB, 
  105.         FALSE) // tell GLWidget not to build just yet  
  106. //
  107. ////////////////////////////////////////////////////////////////////////
  108. {
  109.     // In this case, this component may be what the app wants, 
  110.     // or it may want a subclass of this component. Pass along buildNow
  111.     // as it was passed to us.
  112.     constructorCommon(buildNow);
  113. }
  114.  
  115. ////////////////////////////////////////////////////////////////////////
  116. //
  117. // Called by the constructors
  118. //
  119. // private
  120. //
  121. void
  122. MySlider::constructorCommon(SbBool buildNow)
  123. //
  124. //////////////////////////////////////////////////////////////////////
  125. {
  126.     mouse = new SoXtMouse(ButtonPressMask | ButtonMotionMask | ButtonReleaseMask);
  127.  
  128.     // init local vars
  129.     startCallbacks      = new MyFloatCallbackList;
  130.     changedCallbacks     = new MyFloatCallbackList;
  131.     finishCallbacks     = new MyFloatCallbackList;
  132.     interactive = FALSE;
  133.     value = 0.0;
  134.     sliderWidget = labelWidget = numberWidget = mgrWidget = NULL;
  135.     labelStr = NULL;
  136.     numberVisible = TRUE; // show the number by default
  137.     
  138.     // slider geometry vars which do not depend on window size
  139.     slx1 = sly1 = SIDE;
  140.     thumy1 = THUMB_SPACE;
  141.     thumy2 = thumy1 + BOX_H;
  142.     
  143.     sliderSize.setValue(110, 25);  // default slider size
  144.     
  145.     // Build the widget tree, and let SoXtComponent know about our base widget.
  146.     if (buildNow) {
  147.     Widget w = buildWidget(getParentWidget());
  148.     setBaseWidget(w);
  149.     }
  150. }
  151.  
  152. ////////////////////////////////////////////////////////////////////////
  153. //
  154. //    Destructor.
  155. //
  156.  
  157. MySlider::~MySlider()
  158. //
  159. ////////////////////////////////////////////////////////////////////////
  160. {
  161.     delete startCallbacks;
  162.     delete changedCallbacks;
  163.     delete finishCallbacks;
  164.     if (labelStr != NULL) free(labelStr);
  165.     delete mouse;
  166. }
  167.  
  168.  
  169. ////////////////////////////////////////////////////////////////////////
  170. //
  171. //    This routine draws the entire slider region.
  172. //
  173. // Use: virtual public
  174.  
  175. void
  176. MySlider::redraw()
  177. //
  178. ////////////////////////////////////////////////////////////////////////
  179. {
  180.     if (! isVisible())
  181.     return;
  182.     glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
  183.     
  184.     // compute thum position
  185.     position = slx1 + short(value * (slx2 - slx1));
  186.     thumx1 = position - BOX_L;
  187.     thumx2 = position + BOX_L;
  188.     
  189.     // draw slider surrounding
  190.     SbVec2s size = getGlxSize();
  191.     drawDownUIRegion(0, 0, size[0]-1, size[1]-1);
  192.     
  193.     // now call the routine which does drawing inside the slider top region
  194.     drawSliderTopRegion();
  195. }
  196.  
  197.  
  198. ////////////////////////////////////////////////////////////////////////
  199. //
  200. //  Sets the label string.
  201. //
  202. // Use: public
  203.  
  204. void
  205. MySlider::setLabel(const char *newlabel)
  206. //
  207. ////////////////////////////////////////////////////////////////////////
  208. {
  209.     // out with the old...
  210.     if (labelStr != NULL) free(labelStr);
  211.     labelStr = NULL;
  212.     
  213.     // in with the new...
  214.     if (newlabel != NULL)
  215.         labelStr = strdup(newlabel);
  216.     
  217.     if (getWidget() != NULL)
  218.         doLabelLayout();
  219. }
  220.  
  221. ////////////////////////////////////////////////////////////////////////
  222. //
  223. //  Sets visibility of the numeric field
  224. //
  225. // Use: public
  226.  
  227. void
  228. MySlider::setNumericFieldVisible(SbBool setVisible)
  229. //
  230. ////////////////////////////////////////////////////////////////////////
  231. {
  232.     if (setVisible) {
  233.     if (numberVisible)
  234.         return;    // already visible
  235.     else {
  236.         // make the number visible
  237.         numberVisible = TRUE;
  238.         if (getWidget() != NULL)
  239.         doNumberLayout();
  240.     }
  241.     }
  242.     else {
  243.     if (! numberVisible)
  244.         return;    // already not visible
  245.     else {
  246.         // make the number not visible
  247.         numberVisible = FALSE;
  248.         if (getWidget() != NULL)
  249.         doNumberLayout();
  250.     }
  251.     }
  252. }
  253.  
  254.  
  255. ////////////////////////////////////////////////////////////////////////
  256. //
  257. //  lays out the motif label (if any) and slider relative to it.
  258. //
  259. // Use: private
  260.  
  261. void
  262. MySlider::doLabelLayout()
  263. //
  264. ////////////////////////////////////////////////////////////////////////
  265. {
  266.     int n;
  267.     Arg args[10];
  268.     
  269.     if (labelStr == NULL) {
  270.         
  271.         XtSetArg(args[0], XmNleftAttachment,         XmATTACH_FORM);
  272.         XtSetValues(sliderWidget, args, 1);
  273.         
  274.     if (labelWidget != 0) {
  275.         //??? XtUnmanage first?
  276.         XtDestroyWidget(labelWidget);
  277.         labelWidget = 0;
  278.     }
  279.     }
  280.     else {
  281.     if (labelWidget == 0) {
  282.         
  283.         labelWidget = XtCreateWidget(labelStr, xmLabelGadgetClass, mgrWidget, 
  284.                 NULL, 0);
  285.         
  286.         n = 0;
  287.         XtSetArg(args[n], XmNtopAttachment,     XmATTACH_FORM); n++;
  288.         XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM); n++;
  289.         XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_FORM); n++;
  290.         XtSetArg(args[n], XmNrightAttachment,   XmATTACH_NONE); n++;
  291.         XtSetValues(labelWidget, args, n);
  292.         
  293.         n = 0;
  294.         XtSetArg(args[n], XmNleftAttachment,    XmATTACH_WIDGET); n++;
  295.         XtSetArg(args[n], XmNleftWidget,         labelWidget); n++;
  296.         XtSetArg(args[n], XmNleftOffset,         TEXT_OFFSET); n++;
  297.         XtSetValues(sliderWidget, args, n);
  298.         
  299.         XtManageChild(labelWidget);
  300.     }
  301.     else {
  302.         XtSetArg(args[0], XmNname, labelStr);
  303.         XtSetValues(labelWidget, args, 1);
  304.     }
  305.     }
  306. }
  307.  
  308. ////////////////////////////////////////////////////////////////////////
  309. //
  310. //  lays out the motif numeric text field (if any) and slider relative to it.
  311. //
  312. // Use: private
  313.  
  314. void
  315. MySlider::doNumberLayout()
  316. //
  317. ////////////////////////////////////////////////////////////////////////
  318. {
  319.     int n;
  320.     Arg args[10];
  321.     
  322.     if (! numberVisible) {
  323.         
  324.         XtSetArg(args[0], XmNrightAttachment,         XmATTACH_FORM);
  325.         XtSetValues(sliderWidget, args, 1);
  326.         
  327.     if (numberWidget != NULL) {
  328.         //??? XtUnmanage first?
  329.         XtDestroyWidget(numberWidget);
  330.         numberWidget = NULL;
  331.     }
  332.     }
  333.     else {
  334.     if (numberWidget == NULL) {
  335.         
  336.         n = 0;
  337.         XtSetArg(args[n], XmNhighlightThickness, 1); n++;
  338.         XtSetArg(args[n], XmNcolumns, 4); n++;
  339.         numberWidget = XtCreateWidget("sliderText", xmTextWidgetClass,
  340.         mgrWidget, args, n);
  341.         XtAddCallback(numberWidget, XmNactivateCallback, 
  342.         (XtCallbackProc) MySlider::textFieldCB, (XtPointer) this);
  343.         
  344.         n = 0;
  345.         XtSetArg(args[n], XmNtopAttachment,        XmATTACH_NONE); n++;
  346.         XtSetArg(args[n], XmNleftAttachment,    XmATTACH_NONE); n++;
  347.         XtSetArg(args[n], XmNrightAttachment,   XmATTACH_FORM); n++;
  348.         XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_FORM); n++;
  349.         XtSetValues(numberWidget, args, n);
  350.         
  351.         n = 0;
  352.         XtSetArg(args[n], XmNrightAttachment,   XmATTACH_WIDGET); n++;
  353.         XtSetArg(args[n], XmNrightWidget,         numberWidget); n++;
  354.         XtSetValues(sliderWidget, args, n);
  355.         
  356.         // now set the string to the slider value
  357.         char valStr[6];
  358.         sprintf(valStr, "%.2f", getValue());
  359.         XmTextSetString(numberWidget, valStr);
  360.     
  361.         XtManageChild(numberWidget);
  362.     }
  363. #ifdef DEBUG
  364.     else {
  365.         SoDebugError::post("MySlider::doNumberLayout::menuPick",
  366.         "INTERNAL ERROR");
  367.     }
  368. #endif
  369.     }
  370. }
  371.  
  372.  
  373.  
  374. ////////////////////////////////////////////////////////////////////////
  375. //
  376. // Description:
  377. //      This builds the parent Glx widget, then registers interest
  378. // in mouse events.
  379. //
  380. // Use: virtual protected
  381. Widget
  382. MySlider::buildWidget(Widget parent)
  383. //
  384. ////////////////////////////////////////////////////////////////////////
  385. {
  386.     int n;
  387.     Arg args[10];
  388.     
  389.     //
  390.     // create a top form to hold everything together
  391.     //
  392.     mgrWidget = XtCreateWidget(getWidgetName(), xmFormWidgetClass, parent, NULL, 0);
  393.     // ??? do we need to register this widget class?
  394.     
  395.     //
  396.     // create MySlider and text widget
  397.     //
  398.     sliderWidget = SoXtGLWidget::buildWidget(mgrWidget);
  399.     SoXt::setWidgetSize(sliderWidget, sliderSize);
  400.     mouse->enable(getNormalWidget(), 
  401.         (XtEventHandler) SoXtGLWidget::eventHandler,
  402.         (XtPointer) this);
  403.     
  404.     
  405.     //
  406.     // do layout
  407.     //
  408.     
  409.     n = 0;
  410.     XtSetArg(args[n], XmNtopAttachment,         XmATTACH_FORM); n++;
  411.     XtSetArg(args[n], XmNbottomAttachment,      XmATTACH_FORM); n++;
  412.     XtSetValues(sliderWidget, args, n);
  413.     
  414.     doLabelLayout();
  415.     doNumberLayout();
  416.     
  417.     // manage that slider
  418.     XtManageChild(sliderWidget);
  419.     
  420.     return mgrWidget;
  421.  
  422. }
  423.  
  424. ////////////////////////////////////////////////////////////////////////
  425. //
  426. //  Resize the slider (only) widget
  427. //
  428. // Use: virtual public
  429. void
  430. MySlider::setSliderSize(const SbVec2s &newSize)
  431. //
  432. ////////////////////////////////////////////////////////////////////////
  433. {
  434.     if (sliderWidget != NULL)
  435.      SoXt::setWidgetSize(sliderWidget, newSize);
  436.     sliderSize = newSize;
  437. }
  438.  
  439. ////////////////////////////////////////////////////////////////////////
  440. //
  441. //  Returns the slider (only) widget size
  442. //
  443. // Use: virtual public
  444. SbVec2s
  445. MySlider::getSliderSize()
  446. //
  447. ////////////////////////////////////////////////////////////////////////
  448. {
  449.     return sliderSize;
  450. }
  451.  
  452. ////////////////////////////////////////////////////////////////////////
  453. //
  454. // Process the passed X event.
  455. //
  456. // Use: virtual public
  457.  
  458. void
  459. MySlider::processEvent(XAnyEvent *xe)
  460. //
  461. ////////////////////////////////////////////////////////////////////////
  462. {
  463.     short x, y;
  464.     XButtonEvent *be;
  465.     XMotionEvent *me;
  466.     SbVec2s size = getGlxSize();
  467.     
  468.     switch (xe->type) {
  469.     case ButtonPress:
  470.         be = (XButtonEvent *) xe;
  471.         if (be->button == Button1) {
  472.         
  473.         startCallbacks->invokeCallbacks(value);
  474.         interactive = TRUE;
  475.         
  476.         // check for thumb picking region
  477.         x = short(be->x);
  478.         y = short(size[1] - be->y);
  479.         if (x>thumx1 && x<thumx2 && 
  480.             y>thumy1 && y<thumy2)
  481.             posdiff = x - position;
  482.         else {
  483.             posdiff = 0;
  484.             setValue((x - slx1 - posdiff) / float(slx2 - slx1));
  485.         }
  486.         }
  487.         break;
  488.         
  489.     case ButtonRelease:
  490.         be = (XButtonEvent *) xe;
  491.         if (be->button == Button1) {
  492.         interactive = FALSE;
  493.         finishCallbacks->invokeCallbacks(value);
  494.         }
  495.         break;
  496.         
  497.     case MotionNotify:
  498.         me = (XMotionEvent *) xe;
  499.         if (me->state & Button1Mask)
  500.         setValue((me->x - slx1 - posdiff) / float(slx2 - slx1));
  501.         break;
  502.     }
  503. }
  504.  
  505.  
  506. ////////////////////////////////////////////////////////////////////////
  507. //
  508. //  Sets the slider to this value..
  509. //
  510. // Use: public
  511.  
  512. void
  513. MySlider::setValue(float v)
  514. //
  515. ////////////////////////////////////////////////////////////////////////
  516. {
  517.     // assign the clipped value and check for redraw needs
  518.     float old = value;
  519.     value = (v > 1.0) ? 1.0 : ((v < 0.0) ? 0.0 : v) ;
  520.     
  521.     if (value == old)
  522.         return;
  523.     
  524.     redraw();
  525.     
  526.     // update text field
  527.     if (numberWidget != NULL) {
  528.     char valStr[6];
  529.     sprintf(valStr, "%.2f", value);
  530.     XmTextSetString(numberWidget, valStr);
  531.     }
  532.     
  533.     changedCallbacks->invokeCallbacks(value);
  534. }
  535.  
  536.  
  537. ////////////////////////////////////////////////////////////////////////
  538. //
  539. //  This routine is when the window has changed size
  540. //
  541. // Use: virtual protected
  542.  
  543. void
  544. MySlider::sizeChanged(const SbVec2s &newSize)
  545. //
  546. ////////////////////////////////////////////////////////////////////////
  547. {
  548.     // calculate slider parameters which depends on window size
  549.     slx2 = newSize[0] - SIDE -1;
  550.     sly2 = newSize[1] - SIDE -1;
  551.     
  552.     // reset projection
  553.     glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
  554.     glViewport(0, 0, newSize[0], newSize[1]);
  555.     glMatrixMode(GL_PROJECTION);
  556.     glLoadIdentity();
  557.     glOrtho(0, newSize[0], 0, newSize[1], -1, 1);
  558. }
  559.  
  560.  
  561. ////////////////////////////////////////////////////////////////////////
  562. //
  563. //  Draws the little white maker. subclasses can redefine this routine to
  564. //  make the slider top region look like anything they want.
  565. //
  566. // Use: virtual protected
  567.  
  568. void
  569. MySlider::drawSliderTopRegion()
  570. //
  571. ////////////////////////////////////////////////////////////////////////
  572. {
  573.     MAIN_UI_COLOR;
  574.     glRects(slx1, sly1, slx2, sly2);
  575.     drawThumbUIRegion(thumx1, thumy1, thumx2, thumy2);
  576. }
  577.  
  578. void
  579. MySlider::addStartCallback(MySliderCB *f, void *userData)
  580. { startCallbacks->addCallback((MyFloatCallbackListCB *)f, userData); }
  581.     
  582. void
  583. MySlider::addValueChangedCallback(MySliderCB *f, void *userData)
  584. { changedCallbacks->addCallback((MyFloatCallbackListCB *)f, userData); }
  585.  
  586. void
  587. MySlider::addFinishCallback(MySliderCB *f, void *userData)
  588. { finishCallbacks->addCallback((MyFloatCallbackListCB *)f, userData); }
  589.  
  590. void
  591. MySlider::removeStartCallback(MySliderCB *f, void *userData)
  592. { startCallbacks->removeCallback((MyFloatCallbackListCB *)f, userData); }
  593.     
  594. void
  595. MySlider::removeValueChangedCallback(MySliderCB *f, void *userData)
  596. { changedCallbacks->removeCallback((MyFloatCallbackListCB *)f, userData); }
  597.  
  598. void
  599. MySlider::removeFinishCallback(MySliderCB *f, void *userData)
  600. { finishCallbacks->removeCallback((MyFloatCallbackListCB *)f, userData); }
  601.  
  602.  
  603.  
  604.  
  605. //
  606. ////////////////////////////////////////////////////////////////////////
  607. // static callbacks stubs
  608. ////////////////////////////////////////////////////////////////////////
  609. //
  610.  
  611.  
  612.  
  613.  
  614. //
  615. // called whenever the user types a new value in the text field.
  616. //
  617. void
  618. MySlider::textFieldCB(Widget w, MySlider *p, XtPointer)
  619. {
  620.     // get text value from the label
  621.     char *str = XmTextGetString(w);
  622.     float val;
  623.     if (sscanf(str, "%f", &val))
  624.     p->setValue(val);
  625.     else {
  626.     // reformat the text field
  627.     char valStr[6];
  628.     sprintf(valStr, "%.2f", p->getValue());
  629.     XmTextSetString(w, valStr);
  630.     }
  631.     free(str);
  632.     
  633.     // make the text field loose the focus
  634.     XmProcessTraversal(SoXt::getShellWidget(w), XmTRAVERSE_CURRENT);
  635. }
  636.  
  637.  
  638.